package conf

import (
	"context"
	"database/sql"
	"fmt"
	"sync"
	"time"

	my "gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var baseData *gorm.DB

type MySQL2 struct {
	Host      string `toml:"host"`
	Port      string `toml:"port"`
	UserName  string `toml:"username"`
	Password  string `toml:"password"`
	Database  string `toml:"database"`
	Database2 string `toml:"database2"`
	// 因为是MySQL的连接池，需要对池子做一些规划配置，会给默认值
	// 控制当前程序的MySQL打开的连接数
	MaxOpenConn int `toml:"max_open_conn"`
	// 控制MySQL连接的复用，比如5，最多保存运行5个来复用，当整个Idle什么都没有的情况下
	MaxIdleConn int `toml:"max_idle_conn"`
	// 一个连接的生命周期，这个和MySQL配置有关系，只能小于
	// 比如一个连接用12H，就要换一个连接，保证一定的可用性
	MaxLifeTime int `toml:"max_life_time"`
	// Idle连接最多允许存活多久
	MaxIdleTime int `toml:"max_idle_time"`
	// 作为私有变量，用于控制GetDB 为了防止资源竞争
	lock sync.Mutex
}

// 建立与数据库的连接
func (m *MySQL2) getBaseData() (*gorm.DB, error) {
	// multiStatements=true支持多条语句
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&multiStatements=true&parseTime=true",
		m.UserName, m.Password, m.Host, m.Port, m.Database)
	sqldb, err := sql.Open("mysql", dsn)
	if err != nil {
		return nil, fmt.Errorf("connect to mysql<%s> error,%s", dsn, err.Error())
	}
	baseData, err = gorm.Open(my.New(my.Config{
		Conn: sqldb,
	}), &gorm.Config{})
	if err != nil {
		return nil, fmt.Errorf("connect to mysql<%s> error,%s", dsn, err.Error())
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	// 用当前的db执行一下ping，检查当前的配置有没有错误，避免MySQL参数配错了
	if err := sqldb.PingContext(ctx); err != nil {
		return nil, fmt.Errorf("ping mysql<%s> error,%s", dsn, err.Error())
	}
	return baseData, nil
}
func (m *MySQL2) GetBaseData() *gorm.DB {
	// 比如在多个APP同时调，同时发现db为nil，同时做一个数据库连接的生成
	// 为了防止资源竞争，要在mysql结构体加锁，锁住临界区
	m.lock.Lock()
	defer m.lock.Unlock()
	if baseData == nil {
		// 如果实例不存在 会报错,就初始化一个新的实例
		conn, err := m.getBaseData()
		if err != nil {
			panic(err)
		}
		baseData = conn
	}
	return baseData
}
